package com.yjy.web;

import com.yjy.mdc.wrapper.CompletableFutureMdcWrapper;
import com.yjy.mdc.wrapper.ThreadPoolExecutorMdcWrapper;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.MDC;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.sql.Date;
import java.util.Map;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicLong;
import java.util.stream.Stream;

@Slf4j
@RestController
@RequestMapping("/test")
@AllArgsConstructor
public class TestController {

    private static final Logger logger = LoggerFactory.getLogger(TestController.class);

    @GetMapping("user")
    public User findOne(String name) {
        User user = new User(name, Date.valueOf("1996-06-07"));
        System.out.println(user);
        logger.info("user:{}", user);
        return user;
    }

    @Data
    @AllArgsConstructor
    public class User {
        private String name;
        private Date birthday;
    }

    // 创建线程池
    private static final AtomicLong count = new AtomicLong(0L);
    private static final ThreadFactory factory = r -> {
        Thread thread = new Thread(r, String.format("check-thread-%d", count.getAndIncrement()));
        // 设置异常捕获，executorService.execute()才会打印，executorService.submit()不会打印以下信息
        thread.setDefaultUncaughtExceptionHandler((t, e) -> System.out.println(String.format("线程%s抛出异常：%s", t.getName(), e.getMessage())));
        return thread;
    };
    private static final ThreadPoolExecutorMdcWrapper threadPoolExecutor = new ThreadPoolExecutorMdcWrapper(10, 20, 100L, TimeUnit.SECONDS, new LinkedBlockingQueue<>(100),
            factory, new ThreadPoolExecutor.CallerRunsPolicy());

    @GetMapping("testThreadPool")
    public User testThreadPool() {
        threadPoolExecutor.execute(() -> {
            log.info("testThreadPool 线程1 执行任务！");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });

        threadPoolExecutor.execute(() -> {
            log.info("testThreadPool 线程2 执行任务！");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });

        User user = new User("user", Date.valueOf("1996-06-07"));
        System.out.println(user);
        logger.info("user:{}", user);
        log.info("测试main线程 执行任务！");
        return user;
    }

    @GetMapping("testCompletableFuture")
    public User testCompletableFuture() {
        CompletableFuture<Void> future1 = CompletableFutureMdcWrapper.runAsync(() -> {
            log.info("testCompletableFuture 线程1 执行任务！");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });

        CompletableFuture<Void> future2 = CompletableFutureMdcWrapper.runAsync(() -> {
            log.info("testCompletableFuture 线程2 执行任务！");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });

        User user = new User("user", Date.valueOf("1996-06-07"));
        System.out.println(user);
        logger.info("user:{}", user);
        log.info("测试main线程 执行任务！");
        CompletableFuture.allOf(future1, future2).join();
        return user;
    }

    @GetMapping("testCompletableFuture2")
    public User testCompletableFuture2() {
        CompletableFuture<Void> future1 = CompletableFuture.runAsync(() -> {
            log.info("testCompletableFuture 线程1 执行任务！");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }, threadPoolExecutor);

        CompletableFuture<Void> future2 = CompletableFuture.runAsync(() -> {
            log.info("testCompletableFuture 线程2 执行任务！");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }, threadPoolExecutor);

        User user = new User("user", Date.valueOf("1996-06-07"));
        System.out.println(user);
        logger.info("user:{}", user);
        log.info("测试main线程 执行任务！");
        CompletableFuture.allOf(future1, future2).join();
        return user;
    }

    @GetMapping("testParallelStream")
    public User testParallelStream() {
        Map<String, String> contextMap = MDC.getCopyOfContextMap();
        Integer integer = Stream.of(1, 2, 3, 4, 5).parallel()
                .peek(i -> MDC.setContextMap(contextMap))
                .map(i -> {
                    log.info(">>> 测试ParallelStream线程 i:{}", i);
                    return i;
                })
                // clear right before terminal operation
                .peek(i -> MDC.clear())
                .findFirst().orElse(10);

        //由于初始线程也在流中使用，并且上下文在流中被清除，我们需要重新设置它的初始状态
        MDC.setContextMap(contextMap);
        return new User("user" + integer, Date.valueOf("2023-08-17"));
    }
}
